package com.cdtye.shuoh.controller.play;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.cdtye.shuoh.config.gb28181.bean.RecordInfo;
import com.cdtye.shuoh.config.gb28181.bean.StreamInfo;
import com.cdtye.shuoh.config.gb28181.storage.IRedisCatchStorage;
import com.cdtye.shuoh.config.gb28181.transmit.callback.DeferredResultHolder;
import com.cdtye.shuoh.config.gb28181.transmit.callback.RequestMessage;
import com.cdtye.shuoh.config.gb28181.transmit.cmd.impl.SIPCommander;
import com.cdtye.shuoh.config.gb28181.zlm.ZLMRESTfulUtils;
import com.cdtye.shuoh.domain.device.entity.Device;
import com.cdtye.shuoh.service.device.DeviceChannelService;
import com.cdtye.shuoh.service.device.DeviceService;
import com.cdtye.shuoh.service.play.PlayService;
import com.cdtye.shuoh.util.text.UUID;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;

import javax.sip.message.Response;

/**
 * GB28181视频播放
 * @author ZhongWang Wang
 * @date 2022-12-21
 */
@RestController
@RequestMapping(value = "/play")
@ConditionalOnProperty(value = "sip.enabled", havingValue = "true")
public class PlayController {
    private final static Logger logger = LoggerFactory.getLogger(PlayController.class);

    @Autowired
    private SIPCommander cmder;


    @Autowired
    private IRedisCatchStorage redisCatchStorage;

    @Autowired
    private ZLMRESTfulUtils zlmresTfulUtils;

    @Autowired
    private DeferredResultHolder resultHolder;

    @Autowired
    private DeviceService deviceService;

    @Autowired
    private DeviceChannelService deviceChannelService;

    @Autowired
    private PlayService playService;

    /**
     * 开始播放
     * @param deviceIdentification
     * @param channelId
     * @return
     */
    @GetMapping("/start")
    public DeferredResult<ResponseEntity<String>> play(String deviceIdentification,String channelId) {
        Device device = deviceService.findOneByDeviceIdentification(deviceIdentification);
        StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceIdentification, channelId);

        String uuid = UUID.getUUID();
        DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>();

        resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result);

        if (streamInfo == null) {
            // 发送点播消息
            cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
                logger.info("收到订阅消息： " + response.toJSONString());
                playService.onPublishHandlerForPlay(response, deviceIdentification, channelId, uuid);
            }, event -> {
                RequestMessage msg = new RequestMessage();
                msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
                Response response = event.getResponse();
                msg.setData(String.format("点播失败， 错误码： %s, %s", response.getStatusCode(), response.getReasonPhrase()));
                resultHolder.invokeResult(msg);
            });
        } else {
            String streamId = streamInfo.getStreamId();
            JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
            if (rtpInfo.getBoolean("exist")) {
                //存在推流信息
                RequestMessage msg = new RequestMessage();
                msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
                msg.setData(JSON.toJSONString(streamInfo));
                resultHolder.invokeResult(msg);
            } else {
                //存在推流信息 redis中有，但是streamInfo中没有
                redisCatchStorage.stopPlay(streamInfo);
                deviceChannelService.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
                cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
                    logger.info("收到订阅消息： " + response.toJSONString());
                    playService.onPublishHandlerForPlay(response, deviceIdentification, channelId, uuid);
                }, event -> {
                    RequestMessage msg = new RequestMessage();
                    msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
                    Response response = event.getResponse();
                    msg.setData(String.format("点播失败， 错误码： %s, %s", response.getStatusCode(), response.getReasonPhrase()));
                    resultHolder.invokeResult(msg);
                });
            }
        }

        // 超时处理
        result.onTimeout(()->{
            logger.warn(String.format("设备点播超时，deviceId：%s ，channelId：%s", deviceIdentification, channelId));
            // 释放rtpserver
            cmder.closeRTPServer(device, channelId);
            RequestMessage msg = new RequestMessage();
            msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
            msg.setData("Timeout");
            resultHolder.invokeResult(msg);
        });
        return result;
    }

    /**
     * 结束播放
     * @param streamId
     * @return
     */
    @PostMapping("/stop")
    public DeferredResult<ResponseEntity<String>> playStop(String streamId) {

        logger.debug(String.format("设备预览/回放停止API调用，streamId：%s", streamId));

        UUID uuid = UUID.randomUUID();
        DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>();

        // 录像查询以channelId作为deviceId查询
        resultHolder.put(DeferredResultHolder.CALLBACK_CMD_STOP + uuid, result);

        cmder.streamByeCmd(streamId, event -> {
            StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
            if (streamInfo == null) {
                RequestMessage msg = new RequestMessage();
                msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
                msg.setData("streamId not found");
                resultHolder.invokeResult(msg);
            }else {
                redisCatchStorage.stopPlay(streamInfo);
                deviceChannelService.stopPlay(streamInfo.getDeviceID(), streamInfo.getChannelId());
                RequestMessage msg = new RequestMessage();
                msg.setId(DeferredResultHolder.CALLBACK_CMD_STOP + uuid);
                //Response response = event.getResponse();
                msg.setData(String.format("success"));
                resultHolder.invokeResult(msg);
            }
        });

        if (streamId != null) {
            JSONObject json = new JSONObject();
            json.put("streamId", streamId);
            RequestMessage msg = new RequestMessage();
            msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
            msg.setData(json.toString());
            resultHolder.invokeResult(msg);
        } else {
            logger.warn("设备预览/回放停止API调用失败！");
            RequestMessage msg = new RequestMessage();
            msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
            msg.setData("streamId null");
            resultHolder.invokeResult(msg);
        }

        // 超时处理
        result.onTimeout(()->{
            logger.warn(String.format("设备预览/回放停止超时，streamId：%s ", streamId));
            RequestMessage msg = new RequestMessage();
            msg.setId(DeferredResultHolder.CALLBACK_CMD_STOP + uuid);
            msg.setData("Timeout");
            resultHolder.invokeResult(msg);
        });
        return result;
    }

    /**
     * 获取实时图片
     * @param flvUrl
     * @return
     */
    @GetMapping(value="/getSnap",produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    public byte[] getSnap(String flvUrl){
        return zlmresTfulUtils.getSnap(flvUrl,15,1);
    }


    /**
     * 通道同步
     * @param deviceIdentification
     * @return
     */
    @GetMapping("/sync")
    public DeferredResult<ResponseEntity<Device>> devicesSync(String deviceIdentification){

        if (logger.isDebugEnabled()) {
        }
        logger.debug("设备通道信息同步API调用，deviceIdentification：" + deviceIdentification);

        Device device = deviceService.findOneByDeviceIdentification(deviceIdentification);
        cmder.catalogQuery(device, event -> {
            Response response = event.getResponse();
            RequestMessage msg = new RequestMessage();
            msg.setId(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceIdentification);
            msg.setData(String.format("同步通道失败，错误码： %s, %s", response.getStatusCode(), response.getReasonPhrase()));
            resultHolder.invokeResult(msg);
        });
        DeferredResult<ResponseEntity<Device>> result = new DeferredResult<ResponseEntity<Device>>(2*1000L);
        result.onTimeout(()->{
            logger.warn(String.format("设备通道信息同步超时"));
            // 释放rtpserver
            RequestMessage msg = new RequestMessage();
            msg.setId(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceIdentification);
            msg.setData("Timeout");
            resultHolder.invokeResult(msg);
        });
        resultHolder.put(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceIdentification, result);
        return result;
    }


}
